home *** CD-ROM | disk | FTP | other *** search
/ Die Speccy' 97 / Die Speccy' 97.iso / amiga_system / the_aminet / dev / debug / apurify_v1_2.lha / doc / MOT-APurify.doc < prev   
Text File  |  1995-09-06  |  29KB  |  621 lines

  1.                   MOT-APurify v1.2.1
  2.                   ------------------
  3.  
  4.                 MOTOROLA-syntax version.
  5.  
  6.                  (c) by Samuel DEVULDER
  7.                    Sept. 1995
  8.  
  9.                Samuel.Devulder@info.unicaen.fr
  10.  
  11. DESCRIPTION (SHORT):
  12. --------------------
  13.     This is APurify for compilers with MOTOROLA syntax    asm-files.  As    far
  14.     as I all compilers exept GCC uses such a syntax. If  you're  using  the
  15.     GCC compiler, then read MIT-APurify.doc instead. That version is rather
  16.     a version for  the    DICE  compiler,  but  I  think    it  can  work  with
  17.     other compilers. In the following  of  that  document,  APurify  stands
  18.     for MOT-APurify, and I assume you're using the DICE compiler.
  19.  
  20.     APurify is a program that allows you to detect bad accesses  to  memory
  21.     of your programs without any kind of specific external  devices  (MMU).
  22.     It avoids bugs due to accessing memory not owned by your program.
  23.  
  24.     This version is based on  the  MIT-syntax  version.  This  is  a  small
  25.     improvement of APurify v1.1 on Aminet/dev/debug.  It  may  be  full  of
  26.     bugs, so be carefull !
  27.  
  28.  
  29. INSTALLATION:
  30. ------------
  31.     That archive contains the version of APurify for the DICE  compiler
  32.     as well for other compilers. Here  is  a  description  of  DICE-related
  33.     files of this archive for that version. It also gives you  what  to  do
  34.     with those files to make an installation.
  35.  
  36.     - doc/MOT-APurify.doc    The file you are currently  reading. Put it
  37.                 with all your doc files. It is usefull from
  38.                 time to time.
  39.  
  40.     - doc/History        The whole history.  (this  file is not very
  41.                 usefull for common people). Do whatever you
  42.                 want with it.
  43.  
  44.     - bin/MOT-APurify    The parser tuned  for  the MOTOROLA syntax.
  45.                 Rename it as APurify and put it someware in
  46.                 your path. That program can  be  used  with
  47.                 any compiler that outputs  MOTOROLA  syntax
  48.                 (ie. all compilers except GCC).
  49.  
  50.     - lib/APur-dice.lib    The DICE link-time  library.  Rename  it as
  51.                 APur.lib  and  put  it    someware  in   your
  52.                 library search-path if you  are  using    the
  53.                 DICE  compiler.  It  may  work     well    for
  54.                 other compilers (it is  a  COMMODORE-format
  55.                 library). If that library is not  good    for
  56.                 you (generating undefined labels or  else),
  57.                 then try APur-pdc.lib.    If  it    fails  too,
  58.                 then please contact  me  and  I'll  try  to
  59.                 include a specific version of that  library
  60.                 for that compiler in a future release.
  61.  
  62.     - lib/APur-pdc.dir    The PDC link-time  library.  Rename  it  as
  63.     - lib/APur-pdc.lib    APur.lib  and  put  it    someware  in   your
  64.                 library search-path if you  are  using    the
  65.                 PDC compiler. It may work  well  for  other
  66.                 compilers   (it   is   a   COMMODORE-format
  67.                 library). If that library is not  good    for
  68.                 you (generating undefined labels or  else),
  69.                 please contact me and I'll try to include a
  70.                 specific version of that library  for  that
  71.                 compiler in a future release.
  72.  
  73.     - test/test.c        Source of a stupid test file.  Just here to
  74.                 let  you  remake  the  test   program.     Do
  75.                 whatever you want with it.
  76.  
  77.     - test/test.dice    Test file  Apurify'ed.  Run it  to  see how
  78.                 APurify  is  useful  :-).  (dice  generated
  79.                 file)
  80.  
  81.     - test/test.pdc     Test file  Apurify'ed.  Run it  to  see how
  82.                 APurify is useful :-). (pdc generated file)
  83.  
  84.  
  85. SYNOPSIS:
  86. --------
  87.     Usage: APurify [-revinfo] [flags] <inputfile> [-o <outputfile>]
  88.  
  89.     Where flags can be:
  90.        -br<Ax>    To set the base register
  91.        -tb    To test memory referenced through base register
  92.        -ts    To test memory referenced through stack register
  93.        -tl    To test memory referenced through local stack frame
  94.        -tp    To test pea instructions
  95.        -?,?,-h    To display this usage
  96.  
  97.     Flags can be anywhere on the command line and may be  merged  together.
  98.     But take care that flags that need an extra argument appear in the last
  99.     position. Thus "-tsoPROG.s" is good  and  will  output  a  file  called
  100.     "PROG.s" while "-otsPROG.s" is wrong and  will  output  a  file  called
  101.     "tsPROG.s" ! Here is a short description of arguments and flags:
  102.  
  103.     -revinfo    This displays informations  about APurify  (name,  size and
  104.         date of modules and number of  compilation  done  for  that
  105.         version).
  106.  
  107.     -br<Ax>    This  sets  the  base  register  used  to  reference memory
  108.         in SMALL_DATA model. Usually A4 is used  for  that  perpose
  109.         and that's the default. If A5  is  used  instead  then  add
  110.         -brA5 on your command line.
  111.  
  112.     -tb     This enable APurify to check all referenced  memory through
  113.         the base register (see -br). If you are using a  SMALL_DATA
  114.         model, add this flag on  your  command    line.  By  default,
  115.         APurify won't check  memory  referenced  through  the  base
  116.         register.
  117.  
  118.         NOTE: for safest check, you should always use that  option,
  119.         even if you're not in smalldata model (A4 may  be  used  as
  120.         a temporary register in that case).
  121.  
  122.     -ts     This  enable  APurify to  check memory referenced  by stack
  123.         pointer (SP or A7). By default  APurify  won't  check  such
  124.         memory accesses (to reduce the code size and  increase  the
  125.         runtime speed). That option will detect when  you  have  no
  126.         more room on your stack (stack overflow).
  127.  
  128.     -tl     This enable APurify to check  memory  referenced   by local
  129.         stack pointer (the one that is link'ed and  unlink'ed  when
  130.         enterring and exiting a C-function). By  default,  this  is
  131.         switch off. This  option  allow  APurify  to  detect  stack
  132.         overflow.
  133.  
  134.     -tp     This enable APurify to check indirect  adresses pushed onto
  135.         the stack by using a pea. By  default  this  is  off.  When
  136.         used, that option will check things like "pea  a2@(10)"  or
  137.         the like. This can help  you  with  memory  accessed  by  a
  138.         pointer in a code that has not been APurify'ed. For example
  139.         this is usefull  for  things  like  fread(&ptr[10],10,1,fp)
  140.         because in that case the "pea a2@(10)" used to push on  the
  141.         stack &ptr[10] will be checked and if ptr[10] is not  owned
  142.         by your program, you'll get an APurify error.  Please  note
  143.         that this may no work all the time  since  &ptr[0]  can  be
  144.         translated as "movel a0,sp@-" which  won't be checked.
  145.  
  146.     -o <outputfile>
  147.         This specifies the name of the outputfile. If  ommited    the
  148.         outputfile will be the same as the inputfile (source file).
  149.  
  150.     -?
  151.     -h
  152.     ?        Obvious options.
  153.  
  154.  
  155. DESCRIPTION (A BIT LONGER):
  156. --------------------------
  157.     As a general rule, at the microprocessor level, there is  two  kind
  158.     of ways to access memory. There is direct access and indirect access to
  159.     memory. For example, in C, direct access can be viewed as accessing  to
  160.     global variables. Indirect access corresponds  to  accessing  an  array
  161.     value. More precisely, direct access corresponds to reading or  writing
  162.     a variable whose address is known at compilation  time  (or  since  the
  163.     loading of the program into the memory). Indirect access  is  used    for
  164.     variables whose adress is dynamicaly determined  by  the  program.    For
  165.     example, if p is a pointer to an array allocated by malloc(), *p is  an
  166.     indirect access. Such an access occur also in case of instruction  like
  167.     T[i] where T is a global array, because the  address  of  T[i]  is    not
  168.     known at compilation time, since it depends on the index value i. Using
  169.     indirect access to memory is called indirection.
  170.  
  171.     A regular program must not access memory not owned by it. That kind
  172.     of access can be qualified as illegal.
  173.  
  174.     Illegal direct access  to   memory  is    not  possible, because     by
  175.     definition, only global  variables can be  accessed that  way and those
  176.     variables belongs obviously to the program    (except for code written in
  177.     assembly   language   that    references  absolute   values, for example:
  178.     "btst  #6,$bfe001"; but that  kind of  code  is not a  good programming
  179.     :-)). So we can assume that direct access to memory is always right.
  180.  
  181.     On the other hand,  it is sure    that indirect access to  memory can
  182.     be illegal.  Many bugs are made by    overstepping array  boundaries.  If
  183.     that oversteppings are  in reading a value, there  is not much  trouble
  184.     for over running tasks (it is an error inside your  task); but if it is
  185.     in writing you may directly interfere with other tasks and big mess can
  186.     happen (total breakdown of the system).
  187.  
  188.     APurify works on  that kind of access  by verifying the validity of
  189.     indirect access to memory. It remebers the memory that was allocated by
  190.     the program and check the integrity of  each access. One can think that
  191.     makes a lot of tests ! Well, yes, but APurify is  not  designed  to  be
  192.     used in the general use of programs; just  in  test  phases.  Moreover,
  193.     indirections  do  no  occur  very  often  actually.  Only    array-based
  194.     variables produces indirections.  Thus,  the  variables  on  the  stack
  195.     --although being accessed by  indirection--  are  not  checked  because
  196.     their access is always safe (at least if there is no stack overflow !).
  197.     Also, in SMALL_DATA model, global  variables  access  is  done  through
  198.     indirection, but they are not checked.
  199.  
  200.     If an illegal access is found, APurify displays an error message on
  201.     the error stream of the program (have a look at the full  justification
  202.     of the output when using verbose mode :^). There is two kind of illegal
  203.     accesses. Some are accesses  to  memory  that  doesn't  belong  to  the
  204.     program (it is called  an  access  between  blocks),  some  others  are
  205.     accesses to a part of memory owned by a program and an other  part    not
  206.     owned by it (it is an overstepping  of  a  block).  You  can  see  this
  207.     visually: If [ 1 ] and [ 2 ] represent  two  blocks  allocated  by    the
  208.     program and ( 3 ) the memory accessed, then
  209.  
  210.          ---- [ 1 ] ---- ( 3 ) ---- [ 2 ] ---->
  211.         0                       increasing address
  212.  
  213.     corresponds to the first kind of illegal access and
  214.  
  215.              ---- [ 1 ( ] 3 ) ---- [ 2 ] ----->
  216.     or
  217.              ---- [ 1 ] ---- ( 3 [ ) 2 ] ----->
  218.  
  219.     corresonds to the second kind of access. The first kind is very  common
  220.     but the second is quite rare (it's rather a misaligment problem).
  221.  
  222.     APurify has two output modes. One is verbose an tries to  give    lot
  223.     of informations by using words. The other one is more brief  and  gives
  224.     you the same informations but you'll have to decode them.
  225.  
  226.     When APurify starts and ends, it outputs  the  date/time.  This  is
  227.     useful if you are using logfiles. With that, you can keep all your logs
  228.     in a  single  file    and  retrieve  any  execution  with  it's  date  of
  229.     execution.
  230.  
  231.     In case of an error, APurify displays some  text.  The    first  line
  232.     looks like this one:
  233.  
  234.     **** APURIFY ERROR ! [$<N1>(<N2>) <ATTR> (<TEXT1>)] <TEXT2>:
  235.  
  236.     That line represent  the  accessed    memory.  <N1>  is  the    hexadecimal
  237.     address accessed. <N2> is the length of the access (in decimal). <ATTR>
  238.     represents the type of acess. <TEXT1> allows you to find where in  your
  239.     code the illegal accessed had happened. <TEXT2> describe  the  kind  of
  240.     illegal access.
  241.  
  242.     If the length (<N1>) is 1, then it was a byte access. 2 stands  for
  243.     a short access,  4    for  a    int/long  and  >4  for    movem  instruction.
  244.     Attributes, <ATTR>, can be "R--" or "-W-". The first one represents  an
  245.     access in reading a value and the second an access in writing a value.
  246.  
  247.     The text <TEXT1> look like this:
  248.  
  249.         <NAME>, PC=$<PC#> HUNK=$<HUNK#> OFFSET=$<OFF#>
  250.  
  251.     <NAME> is the name of the subroutine where the  error  occured.  It  is
  252.     always displayed (even if it is a "static" one). The rest of  the  line
  253.     can be partially displayed, showing as much informations as APurify can
  254.     get. <PC#> is a hexadecimal address pointing to  the  instruction  that
  255.     produced the error. <HUNK#> and <OFF#> are    the  hunk  number  and    the
  256.     relative offset of <PC#>. Using <HUNK#> and <OFF#> and a  disassembler,
  257.     you can very easilly find where your code is bad (BTW, I use dobj  from
  258.     netdcc, (c) by Matt Dillon). Please note  that  <PC#>  can  point  some
  259.     instruction before the faultly one. In that case, it will  point  to  a
  260.     PEA followed by a JSR. As those instructions does not  belong  to  your
  261.     code (they are APurify stuff), the involved instruction  is  the  third
  262.     one. That will happen only if  an  instruction  references    memory    two
  263.     times and if the first access is wrong. It is a little bit annoying but
  264.     it is better than nothing and it is quite rare :-).
  265.  
  266.     The remaining lines show the context  of  the  illegal    access.  It
  267.     gives you informations about the  surronding  memory  blocks  owned  by
  268.     your program. Each    block  is  displayed  according  to  the  following
  269.     pattern:
  270.  
  271.                [$<N1>(<N2>) <ATTR> (<TEXT>)]
  272.  
  273.     where <N1> is the hexadecimal address of the beginning  of    the  block,
  274.     <N2> its length (in decimal). Note that  the  length  may  seem  to  be
  275.     longer than the one allocated by malloc() and  the  address  may  point
  276.     before the one you obtained via malloc(). This is not wrong !  In  fact
  277.     you must know that the malloc() subroutine may  add  some  informations
  278.     (like an double-chained list or the length of the  allocation)  to  the
  279.     block you've requested. Those extra informations  are  put  before  the
  280.     address you recieve. That explain this behavior.  In  this    version  of
  281.     APur-dice.lib, this takes 8 extra bytes. So if you allocate  10  bytes,
  282.     don't be suprised if APurify thinks you've requested 18 bytes.
  283.  
  284.     <ATTR> are 3 status characters RWS
  285.  
  286.     where R means: read-enable block
  287.           W means: write-enable block
  288.           S means: system block (block not controlled by the program).
  289.  
  290.     If one access is forbidden, the letter '-' replaces  the  corresponding
  291.     character. <TEXT> is actually  the    name  of  the  procedure  that    has
  292.     allocated the block. If it ends with "*" that block was allocated by  a
  293.     call to a subroutine not parsed by APurify during the execution of    the
  294.     one indicated (a library call, maybe).
  295.  
  296.     With each block you can find an offset. That offset is the distance
  297.     between that block and the faultly address. In verbose  mode,  you    can
  298.     see some text explaining things about the relative position of a  block
  299.     and the accessed memory. In non-verbose  mode  you    can  just  see    the
  300.     offsets followed by the blocks. The shorter offset is  displayed  first
  301.     since that block is the one that is more likely overstepped.
  302.  
  303.     When an illegal writing occur (the only dangerous thing you can  do
  304.     by indirection, indeed), APurify tells you    to  that  error  is  really
  305.     dangerous and asks if you wish to stop your program. If  you  wish    so,
  306.     exit() is called. You can also ignore that error  or  ignore  all  such
  307.     errors (but then you'll surely meet the guru !).
  308.  
  309.     APurify checks the memory allocated but not freed by  the  program.
  310.     (in fact, it detects non deallocated-blocks on library-closing time).
  311.  
  312.     It  knows  about  memory  location  independant  of   the   program
  313.     execution. That is to say, the first kilobyte of memory  that  contains
  314.     interrupt vectors of the 680x0 processor, the program segments and    the
  315.     stack. Accessing to those blocks will not be illegal. They    got  the  S
  316.     attribute (for SYSTEM blocks).
  317.  
  318.     It takes into  account    memory    block  allocated  by  malloc()  and
  319.     AllocMem(), and indirect allocated block (by OpenScreen() for example).
  320.     But I did not test the last kind of allocation. Anyway,  it  should  be
  321.     ok, because APurify patches AllocMem()  &  FreeMem()  entries.  Thus  a
  322.     program can access to the bitplanes of one of its screen without error.
  323.  
  324.     If  the  program  makes  a  legal  access,   but   attributes    are
  325.     incompatible  with    the  access-kind,  a  protection-error    message  is
  326.     displayed. Actually only the first    kilobyte  is  read/write-protected.
  327.     But it may change in the future.
  328.  
  329.     In order to speed up block  searching,    APurify  uses  a  cache  of
  330.     recently accessed blocks. Thus, even if there  is  a  large  amount  of
  331.     memory blocks, execution should not be slowed down    too  much.  (but  I
  332.     must say I doubt it is efficient enough).
  333.  
  334.  
  335. HOW TO USE APURIFY:
  336. ------------------
  337.     One can see APurify as a pre-assembler. It must be used on assembly
  338.     language sourcefile just before the assembler takes place. It scan    the
  339.     file and change it a bit so that APur.lib can be used.
  340.  
  341.     Normal way to use it for a C program is to:
  342.  
  343.     - compile C sourcefiles and leave assembly language source (.a).
  344.     - use APurify on each .a file.
  345.     - compile your .a file to get a .o file
  346.     - link all .o files together with APur.lib.
  347.  
  348.     For example, using dcc (DICE) on prog.c that gives
  349.  
  350.     CLI> dcc -a prog.c -o prog.a
  351.     CLI> APurify -tb prog.a
  352.     CLI> dcc -s prog.a -o prog -lAPur
  353.  
  354.     As you can see, APurify needs no change to your C  files  to  be  used.
  355.     However, the library must be opened by calling AP_Init() in the  main()
  356.     function. Note that now, you need not call AP_Close() anymore (even  if
  357.     you can still call it but for nothing (it is  automatically  called  on
  358.     exit()). But do not use Exit() to abort your  program,  I  think  it'll
  359.     crash if  APurify  is  running.  If  you  must  use  Exit()  then  call
  360.     AP_Close() just before calling Exit(). The explantion is simple:  since
  361.     some system functions are patched, if a program exits  without  closing
  362.     the library, those patch will be corruped, pointing to a code  that  is
  363.     nomore in memory and you'll  meet  the  guru  (ie:  the  computer  will
  364.     crash)... (You've been warned :-).
  365.  
  366.     If you forget to open the library, a warning message will tell    you
  367.     about that and the program will go just as if it  wasn't  processed  by
  368.     APurify.
  369.  
  370.     You can disable/enable printing of messages by    making    a  call  to
  371.     AP_Report(flag). If  flag  is  true  (ie.  different  from  zero)  then
  372.     printing is enabled, if it is false (ie. equal to zero), no output will
  373.     be done. This is usefull for startup-codes. For  example,  if  you    are
  374.     using the argv[] array in C, APurify will make  a  lot  of    false-error
  375.     printing. This is because the values pointed by this array is allocated
  376.     before  the  library  is  opened.  You  can  avoid    this   by   calling
  377.     AP_Report(0) before, and AP_Report(1) after, the code that uses argv[].
  378.  
  379.     When debugging an APurify'ed program, you can put a  breakpoint  on
  380.     a function called AP_Err(). That function AP_Err() is called each  time
  381.     APurify detects an error. With that, you'll have the occasion  to  look
  382.     at your program just before a faultly memory-access occur.
  383.  
  384.     You can switch    from  a  verbose  output  to  a  shorter  one  with
  385.     AP_Verbose(flag). IF flag is true then the verbose mode is on. If it is
  386.     false then only short messages will be printed. Some people prefer    the
  387.     later so that is the default. If you perfer the verbose ouput then    put
  388.     AP_Verbose(1)  someware  in  your  code  and  you'll  get  some  longer
  389.     explanations about illegal accesses.
  390.  
  391.     You can specify a logfile where APurify can put its errors.  To  do
  392.     this, set the environment variable "APlog" (file env:APlog) to  a  name
  393.     of a logfile. If this variable is set, then APurify will append all its
  394.     outputs to the file indicated.
  395.  
  396.     You can use APurify on any  language  that  generates  a  temporary
  397.     assembly language sourcefile (included assembly itself :-) ). You  must
  398.     notice too, that you can use it on programs for which no source-code is
  399.     available (or .o files without .asm files). For  that,  use  a  program
  400.     that  can  do  reverse  engineering  on  your  executable    (ie:   that
  401.     disassembles the executable and  produces  a  .asm    file  ready  to  be
  402.     assembled). Then, with minor changes (prepend '_'  and  append  ':'  to
  403.     every interesting labels, put a call to AP_Init in    the  right  place),
  404.     you get a file ready to be processed by APurify. If the processed  file
  405.     has a HYNK_SYMBOL then you are very lucky and  you    need  not  work  on
  406.     labels. You then just have to find the "_main:" and add "jbsr _AP_Init"
  407.     as the first instruction of the "_main:" subroutine.
  408.  
  409.     Note:  you  can  use  ADIS  (by Martin Apel)  on  aminet  to do reverse 
  410.     engineering (it seems to be quite good a tool to do it).
  411.  
  412.  
  413. EXAMPLE:
  414. -------
  415.     As an example, let's look at the test.dice program. You'll see  how
  416.     you can use the APurify report it produces    to  find  what's  wrong  in
  417.     the program. For this, I've included in  that  document  the  commented
  418.     report. My comments/explanations appear on lines beginning with a "#".
  419.  
  420.     **** APurify started on Mon Sep 04 23:13:56 1995
  421.  
  422.     #
  423.     # Well, the report started...
  424.     #
  425.  
  426.     **** APURIFY ERROR ! [$00251900(4)  R--  (_main,  PC=$0025c36a  HUNK=$0
  427.     OFFSET=$232)] accessed between:
  428.         -29     [$00251920(23) RW- (_main*)]
  429.         +44861  [$002469b8(12) RW- (_main*)]
  430.  
  431.     # Hum... First hit... it is an error in reading something in the main()
  432.     # procedure between two blocks already  allocated.    The  nearest  block
  433.     # appears in first position, so we can think that the error was done by
  434.     # accessing an array allocated in main() with a negative index. We  can
  435.     # look at the code to find what is wrong with it. Using DOBJ, we  found
  436.     # at offset $232 in the first hunk the following code:
  437.     #
  438.     #        00.00000232  4852               PEA.L   (A2)
  439.     #        00.00000234  4eb9 AP_WriteL        JSR       AP_WriteL
  440.     #        00.0000023a  24ab ffd8           MOVE.L -40(A3),(A2)
  441.     #
  442.     # The  pointed  instruction  is  a    PEA  followed  by  a  JSR.  So    the
  443.     # interesting instruction is the third one. This corresponds to  the  C
  444.     # code:
  445.     #
  446.     #                   a[0]=b[-10]
  447.     #
  448.     # Hence we've discovered a first error in the code. Note  that  -25  is
  449.     # the distance (in bytes) between the end of the  accessed  memory  and
  450.     # the beginning of the array. This is not the  difference  between    the
  451.     # beginning address of the two blocks!
  452.     #
  453.  
  454.     **** APURIFY ERROR ! [$002469c4(4)  R--  (_main,  PC=$0025c39a  HUNK=$0
  455.     OFFSET=$262)] accessed between:
  456.         +1        [$002469b8(12) RW- (_main*)]
  457.         -44937  [$00251950(776) RWS (segment Module CLI)]
  458.  
  459.     #
  460.     # Well... here it seems to be an access just after an allocated  block.
  461.     # the offset +1 is the distance in bytes between the accessed block and
  462.     # a allocated block. The situation is like this:
  463.     #
  464.     #              ---------[ 1 ]( 2 )---------->
  465.     #
  466.     # Where "[ 1 ]" is the allocated block and "( 2 )" the accessed  block.
  467.     # If we look in the code, we find:
  468.     #
  469.     #        00.00000262  4aaa 0004           TST.L   4(A2)
  470.     #
  471.     # that correponds to the test done by "if(a[1] == 0)". This is an error
  472.     # since the array 'a' is just 16-12=4 bytes long. So a[1] points out of
  473.     # the array!
  474.     #
  475.  
  476.     **** APURIFY ERROR !  [$002469c2(4)  R--  (_read_shifted,  PC=$0025c282
  477.     HUNK=$0 OFFSET=$14a)] accessed across the ending boundary of:
  478.         -2        [$002469b8(12) RW- (_main*)]
  479.  
  480.     #
  481.     # Hehe another error... Damn !  That test  program is  FULL  of  bug  !
  482.     # Yes, but that one is an other kind of error. It is an access across a
  483.     # boundary. That occur in the read_shifted() code. We need not look  in
  484.     # the asm file to see the  error.  Here  it  is  a    misaligment  error.
  485.     # Visually that gives:
  486.     #
  487.     #               ------------[ 1(]2 )----------->
  488.     #
  489.     #           [ 1 ] = allocated       ( 2 ) = accessed.
  490.     #
  491.  
  492.     ****  APURIFY  ERROR  !  [$002469c0(4)  R--  (_read_long,  PC=$0025c29e
  493.     HUNK=$0 OFFSET=$166)] accessed between:
  494.         -44941  [$00251950(776) RWS (segment Module CLI)]
  495.         +179933 [$00219e64(3200) RWS (standard stack frame of task)]
  496.  
  497.     #
  498.     # That error is strange! It is  not  an  access  to  an  array  with  a
  499.     # negative index as one think immediately: We never call read_long() in
  500.     # such a way. Indeed, the accessed memory  was  right  some  times    ago
  501.     # since it lays in the array 'a' (look at the second  hit).  Hence,  it
  502.     # must be an access to a freed memory. That  error    is  then  obviously
  503.     # found in the code:
  504.     #
  505.     #              free_arg(a); read_long(a).
  506.     #                   ^^^^^^^^^^^^
  507.     # NOTE: You can see that the program ran with a stack of 3200 bytes.
  508.     #
  509.  
  510.     **** APURIFY ERROR ! [$00000004(4) R--  (_read_page_zero,  PC=$0025c2de
  511.     HUNK=$0 OFFSET=$1a6)] accessed on a read-protected block:
  512.         +4        [$00000000(1024) --S (Basic 680x0 vectors)]
  513.  
  514.     #
  515.     # Here the error is obvious, were are reading the zero-page. If it    was
  516.     # in writing, that error would be very dangerous.
  517.     #
  518.  
  519.     ****  APURIFY  WARNING  !  Closing    library  without  deallocation     of
  520.     the following block(s):
  521.         - [$00252060(408) RW- (_main*)]
  522.         - [$002635e8(12008) RW- (_main*)]
  523.         - [$002664d0(40008) RW- (_main*)]
  524.  
  525.     #
  526.     # The program has exit()ed. APurify tells us that we've forget to  free
  527.     # those blocks. It    is  a  case  of  memory  leak.    Those  blocks  were
  528.     # allocated in main(). They appear in order of allocation.  Those  were
  529.     # allocated and lost by
  530.     #
  531.     #           a=malloc(4),malloc(400),malloc(12000),malloc(400000)
  532.     #
  533.     # since the ",,," returns the leftmost value.
  534.     #
  535.  
  536.     **** APurify ended on Mon Sep 04 23:13:59 1995
  537.  
  538.     #
  539.     # Well... done :-).
  540.     #
  541.  
  542.     NOTE: I hope this example is clear enough.. but I'm not sure.. tell  me
  543.     :^).
  544.  
  545.  
  546. LEGAL PART:
  547. ----------
  548.     That program is provided 'AS IS'. I  am  not  responsible  for  any
  549.     dammage it can cause (but I am responsible for the benefits it can give
  550.     to you :-). Use that software at you own risks.
  551.  
  552.     That program is FREEWARE. You can use and distribute it as long  as
  553.     you keep the archive  intact  (no  adulteration  of  files  except  for
  554.     compression). It can't be sold without my agreement (except  a  minimal
  555.     amount for media support). You must ask me for commercial use  of  (any
  556.     part of) that product. I keep all my rights on  that  program  and    its
  557.     future releases. I can modify that software without telling it  to    the
  558.     users.
  559.  
  560.     If you wish, you can send me a postcard or anything else  you  want
  561.     (money, documentation, amiga, hardware  stuff,  ...)  in  exchange  for
  562.     using APurify. But there is no obligation :-). My postal address is:
  563.  
  564.         M. DEVULDER Samuel
  565.         1, Rue du chateau
  566.         59380 STEENE
  567.         FRANCE
  568.  
  569.     (yes I'm french !). You can  send  suggestions  or  bugs  to  my  email
  570.     address:
  571.  
  572.         devulder@info.unicaen.fr
  573.  
  574.  
  575. NOTES:
  576. -----
  577.     My configuration is: one old A500 (1989), 2Mo RAM, 1  diskdrive,  1
  578.     HARD_DRIVE [300Mo, 10% full :-)], KS1.3 and a lot of  patience  (ah,  I
  579.     wish I had an A4000/040/33Mhz that does  not  meet    the  guru  all    the
  580.     time !).
  581.  
  582.     It has been compiled with freedice 2.06.37.
  583.  
  584.     I had the idea of that program    after  a  chat    with  Cedric  BEUST
  585.     (AMIGA NEWS) on IRC (Internet Relay Chat). Thanks Cedric !
  586.  
  587.     All marks are proprietary of their respective owners.
  588.  
  589.     There are some programs like APurify. For example,  FORTIFY  (Simon
  590.     P. Bullen), but  it  only  detects    illegal  writes  to  boundaries  of
  591.     allocated blocks. Thus it can't detect big oversteps and  oversteps  in
  592.     reading and the detection is not real-time. Enforcer can detect illegal
  593.     access to memory (I think), but it needs a special device (MMU).
  594.  
  595.  
  596. HINTS & TIPS:
  597. ------------
  598.     You can see some memory leaks with that version of APurify.  It  is
  599.     not really good but it can help. Memory leak  occur  when  a  block  of
  600.     memory is nomore pointed by your  program.    Those  memory  blocks  will
  601.     necessary be displayed when your  program  exit()s.  So  with  all  the
  602.     messages printed on that occasion, you can find such  blocks.  I  known
  603.     this is not so great, but I think it can help you a little    bit  (maybe
  604.     in a future version I'll build some code to really check memory leaks).
  605.  
  606.  
  607. BUGS:
  608. ----
  609.     APurify don't known public memory where a program can read or write
  610.     without having allocated it. Thus, it  will  report  an  error  when  a
  611.     program reads or writes values in a message obtained  through  GetMsg()
  612.     calls. Use AP_Report() to avoid such reports.
  613.  
  614.     It can display messages about closing the library  without  freeing
  615.     some memory blocks. This is due to printf() that allocates memory  that
  616.     is free'd on exit. This is not a real bug, but you can  avoid  this  by
  617.     doing a AP_Report(0) just before exiting. But you must notice  that  it
  618.     is better to display false bugs than to not display real ones.
  619.  
  620.     Certainly more bugs, but I'm waiting for your bug-reports.
  621.